/**
 * @version 1.0
 * @created 16 November 2010
 *
 * HibernateDAO
 *
 * Copyright @ 2010
 * All Rights Reserved.
 * CONFIDENTIAL AND TRADE SECRET
 *
 */
package com.ces.knacky.framework.dao;

import java.util.List;

import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.springframework.orm.hibernate3.HibernateInterceptor;

import com.ces.knacky.framework.model.IEntity;

/**
 * It represents Hibernate access layer for the CRUD operations specifications provided in the
 * CommonDAO interface.
 *
 * @see CommonDAO
 * @see IEntity
 * @author bipul_sinha
 *
 */

public class HibernateDAO extends HibernateInterceptor implements CommonDAO {
	/**
	 * Hibernate Session Factory to manage session and second level cache.
	 */
	private SessionFactory sessionFactory;
	/**
	 * Hibernate session object taken from SessionFactory.
	 */
	private Session session;

	/**
	 * Initialization method to initialize session object from session factory. Method explicitly
	 * Configured in beansdefinition.xml file. Constructor is not used due non-initialization of
	 * session factory during the load of HibernateDAO class. Thus, lazy initialization of init
	 * method is used to initialize sessionfactory and session.
	 */
	public void init() {
		session = sessionFactory.openSession();

	}

    /**
     * It is used to add/save an object. The object should be of type IEntity.
     *
     * @param 	entity
     * 			Represents object to be added/saved to the database.
     */
	public boolean add(IEntity entity) {
		Transaction tx = session.beginTransaction();
		session.saveOrUpdate(entity);
		tx.commit();
		return true;
	}
	/**
     * It is used to save a transient IEntity object and return persistent object after database
     * operation.
     * 
     * @param 	IEntity
     * 			Transient object to be saved.
     * @return	Integer
     *   		Persistent Id of the object after save operation.
     */
	public Integer save(IEntity entity){
		Transaction tx = session.beginTransaction();
		Integer  savedObjectId = (Integer) session.save(entity);
		tx.commit();
		return savedObjectId;
	}
    /**
     * It is used to physically delete object from the database. It takes entity object and Id for
     * deletion.
     *
     * @param 	entity
     * 			Represents the entity to be physically deleted.
     * @param 	Id
     * 			Represents identifier of the entity to be deleted.
     */
	public boolean delete(IEntity entity) {
		session.delete(entity);
		return true;
	}

	/**
	 * It takes an HQL query as a parameter and return list of objects.
	 *
	 * @param 	query
	 * 			Represents HQL query to be executed.
	 * @return	List
	 * 			Represents list of IEntity objects.
	 */
	public List<? extends IEntity> list(String query) {
		Query queryObject = session.createQuery(query);
		return queryObject.list();
	}
	/**
     * It is used to load the persistent object from the database. It takes Id and the name of
     * entity to be loaded.
     *
     * @param 	clazz
     * 			Represents fully qualified name of the class of whose entity to be loaded.
     * @param 	Id
     * 			Represents Id of the entity to be loaded.
     * @return	IEntity
     * 			Represents the loaded persistent entity.
     */
	public IEntity load(Class<? extends IEntity> clazz, Integer id) {
		return (IEntity) session.load(clazz, id);
	}
    /**
     * It is used to update/modify an entity. It takes entity as a parameter to be updated.
     *
     * @param 	entity
     * 			Represents entity to be modified/updated in the database.
     */
	public boolean update(IEntity entity) {
		Transaction tx = session.beginTransaction();
		session.update(entity);
		tx.commit();
		return true;
	}
	/**
     * It is used to fetch results from the database using description field. It returns list of
     * objects whose description matches in the DB with the specified parameter.
     *
     * @param 	name
     * 			Represents POJO class from where the description will be matched.
     * @param 	description
     * 			Represents the value of description field whose objects needs to be returned.
     * @return	List
     *			Represents list of objects fetched from the database.
     */
	public List<IEntity> findByDescription(Class<? extends IEntity> clazz, String description) {
		Query query = prepareQuery(clazz, description);
		return query.list();
	}
	/**
     * It is used to fetch only the first object which matches the criteria. It is similar to
     * findByDescription() method however returns only the first object unlike list of objects.
     *
     * @param 	name
     * 			Represents POJO class from where the description will be matched.
     * @param 	description
     * 			Represents the value of description field whose objects needs to be returned.
     * @return	IEntity
     * 			Represent the first object fetched from the DB.
     */
	public IEntity findFirstByDescription(Class<? extends IEntity> clazz, String description) {
		Query query = prepareQuery(clazz, description);
		query.setMaxResults(1);
		List <IEntity> entityList = query.list();
		return entityList.size() > 0 ? entityList.get(0): null;
	}
	/**
	 * Returns session factory object initialized from beansdefinition.xml file.
	 *
	 * @return	SessionFactory
	 * 			Represents session factory object initialized from beansdefinition.xml file.
	 */
	public SessionFactory getSessionFactory() {
		return sessionFactory;
	}
	/**
	 * Used to initialize session factory from the configured bean/source from configuration file.
	 *
	 * @param 	sessionFactory
	 * 			Represents sessionFactory to be set from the configured bean source.
	 */
	public void setSessionFactory(SessionFactory sessionFactory) {
		this.sessionFactory = sessionFactory;
	}

	/**
	 * Represents session initialized from session factory.
	 *
	 * @return	session
	 * 			Hibernate Session object.
	 */
	public Session getSession() {
		return session;
	}

	/**
	 * Used to set the session object.
	 *
	 * @param 	session
	 * 			Represents Hibernate session object.
	 */
	public void setSession(Session session) {
		this.session = session;
	}
	/**
	 * Method used to prepare query.
	 * @param 	clazz
     * 			Represents POJO class from where the description will be matched.
     * @param 	description
     * 			Represents the value of description field whose objects needs to be returned.
     * @return	Query
     * 			Represent query object prepared using specified parameters.
     */
	private Query prepareQuery(Class<? extends IEntity> clazz, String description){
		Query query = session.createQuery("from " + clazz.getName() + " Where description = '" + description + "'");
		return query;
	}
	
	/**
	 * Method used to prepare query.
	 * 
	 * @param 	statement
     * 			Represents update query to be executed. 
     * @return	int
     * 			Represent number of records updated.
     */
	public int batchUpdate(String statement){
		Query query = session.createQuery(statement);
		return query.executeUpdate();
		
	}
}
